let utils = (function(){
	let utils={}
	/**
	 * @description  获取设备的名称及版本
	 * @return {object} 
	 */
	function os() {
		var ua = navigator.userAgent;
		var os = {};
		var funcs = [
			function() {
				//wechat
				var wechat = ua.match(/(MicroMessenger)\/([\d\.]+)/i);
				if (wechat) {
					//wechat
					os.wechat = {
						version: wechat[2].replace(/_/g, ".")
					};
				}
				return false;
			},
			function() {
				//android
				var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
				if (android) {
					os.android = true;
					os.version = android[2];
					os.isBadAndroid = !/Chrome\/\d/.test(window.navigator.appVersion);
				}
				return os.android === true
			},
			function() {
				//ios
				var iphone = ua.match(/(iPhone\sOS)\s([\d_]+)/);
				if (iphone) {
					//iphone
					os.ios = os.iphone = true;
					os.version = iphone[2].replace(/_/g, ".");
				} else {
					var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
					if (ipad) {
						//ipad
						os.ios = os.ipad = true;
						os.version = ipad[2].replace(/_/g, ".");
					}
				}
				return os.ios === true
			}
		];
		for(var i =0;i<funcs.length;i++){
			var result = funcs[i]()
			if(result){
				break;
			}
		}
		
		return os;
	}
	
	/**
	 * 格式化日期
	 * @param {*} date 日期
	 * @param {*} template 格式化模版规则
	 * @return {String}
	 */
	function formatDate(date,template = "{0}年{1}月{2}日 {3}时{4}分{5}秒"){
		// 将日期中的数字提取出来
		let dateArr = date.match(/\d+/g)
		// 将template中的{数字}进行替换
		return template.replace(/\{(\d+)\}/g,(content,$1)=>{
			// content是匹配到的正则内容，$是分组里的内容
			// 按照模版返回替换的数据，并进行补零操作
			let time = dateArr[$1]?dateArr[$1]:'00'
			return  time.length<2?'0'+time:time
		})
		
	}
	/**
	 * 获取星期几
	 * @param {*} date 日期
	 * @return {String} 周['日','一','二','三','四','五','六',]
	 */
	function getWeek(date){
		let weekNum = ['日','一','二','三','四','五','六']
		date = date?date:(new Date()).getTime()
		date = new Date(date)
		let week = date.getDay();
		return '周'+weekNum[week]
	}
	/**
	 * 获取url的query，转为对象
	 * @param {string} url 网址 http://localhost:8080/#/pages/tabbar/user/card-preview?employeeId=1&storeId=45&preview=1
	 * @return {Object} {a:1,b:2}
	 */
	function queryUrlParmas(url){
		let obj = {}
		url.replace(/([^?=&#]+)=([^?=&#]+)/g,(...[,$1,$2])=>{obj[$1]=$2})
		url.replace(/#([^?=&#]+)/g,(...[,$1])=>obj['hash']=$1)
		return obj;
	}
	/**
	 * 格式化手机号:中间段隐藏
	 * @param {string} phone 手机号
	 * @return {string} 如：135****4756
	 */
	function formatPhone(phone){
		return phone.replace(/(\d{3})(\d{4})(\d{4})/,(content,$1,$2,$3)=>{
			return $1+'*'.repeat($2.length)+$3
		})
	}
	/**
	 * 格式化数字：千分位
	 * @param {string} num 12345678
	 * @return {string} 如：12,345,678
	 */
	function formatMilli(num){
		let nums = num.split('.')
		let before = nums[0].replace(/\d{1,3}(?=(\d{3})+$)/g,(...[content])=>content+',')
		return nums[1]?before+'.'+nums[1]:before
	}
	
	/**
	 * 获取文件的扩展后缀
	 * @param {Object} val
	 * @example utils.getExt('微信图片_20200702143103.7z') 输出:7z
	 * @return {String}
	 */
	function getExt(val){
		let filename=file;
		let index1=filename.lastIndexOf(".")+1;
		let index2=filename.length
		let type=filename.substring(index1,index2);
		return type;
	}
	
	/**
	 * 类型检查
	 * @description 自动将[isNumber....]挂载到utils中
	 * @example  utils.isNumber(1)...
	 * @return {Boolean}
	 */
	;(function (utils) {
	    let obj = {
	        'isNumber': "Number",
	        'isObject': 'Object',
	        'isArray': 'Array',
	        'isNull': 'Null',
	        'isUndefined': 'Undefined',
	        'isSymbol': 'Symbol',
	        'isDate': 'Date',
			'isMap': 'Map'
	    }
	    let _toString = obj.toString
	    for (let key in obj) {
	        // 通过判断toString.call([1,2,3]) 是否为[object Array],来达到检测目的
	        let reg = new RegExp("\\[object " + obj[key] + "\\]")
	        utils[key] = function () {
	            let val = _toString.call(arguments[0])
	            return reg.test(val)
	        }
	    }
	})(utils)
	/**
	 * 拷贝对象
	 * @param {Object} obj
	 */
	function deepCopy(obj){
		let newObj = {}
		for(let key in obj){
			if(obj.hasOwnProperty(key)){
				if(utils.isObject(obj[key])){
					newObj[key] = deepCopy(obj[key])
				}else{
					newObj[key] = obj[key]
				}
			}
		}
		return newObj
	}
	/**
	 * 合并2个对象
	 * @param {Object} obj1
	 * @param {Object} obj2
	 */
	function merge(obj1,obj2){
		let newObj = deepCopy(obj1);
		for(let key in obj2){
			if(obj1.hasOwnProperty(key)){
				if(utils.isObject(obj2[key])){
					newObj[key] = merge(obj1[key],obj2[key])
				}else{
					newObj[key] = obj2[key]
				}
			}else{
				newObj[key] = obj2[key]
			}
		}
		return newObj
	}
	/**
	 * 组合函数，串行执行
	 */
	const compose = (fns) =>{
		if(!Array.isArray(fns)){
			fns = [fns]
		}
		return function(arg){
			return fns.reduce((prev,next)=>prev.then(()=>next()),Promise.resolve())
		}
	}
	/**
	 * 数据存储
	 */
	class Storage {
		constructor(options) {
			// 默认配置
			let defaultOptions = {
				nameSpace:'__',// 数据存在命名前缀
				storeType:'localStorage',// 数据存储类型
				expiresSuffix:'__expires',// 过期时间后缀
			}
			// 合并配置
			this.options = Object.assign({},defaultOptions,options)
			this.store = window[this.options.storeType]
			this.__init()
		}
		// 检测所有的存储数据是否过期,过期删除
		__init(){
			// 获取storage中的所有keys
			const keys = Object.keys(this.store)
			// 
			const reg = new RegExp(this.options.expiresSuffix,'g')
			if(!keys.length) return false;
			keys.map(item=>{
				// 如果存在过期时间
				if(reg.test(item)){
					// 当前时间
					const now = Date.now()
					// 获取过期时间
					const expires = Number(this.store.getItem(`${item}`) || now+1)
					// 当前时间大于过期时间，删除数据
					if(now>=expires){
						let removeKey = item.replace(reg,'')
						this.remove(removeKey)
						return ''
					}
				}
			})
		}
		get(key){
			key = this.getKey(key)
			const now = Date.now()
			// 过期时间：如果没有过期时间，设置过期时间为当前时间+1，及永远不过期
			const expires = Number(this.store.getItem(`${key}${this.options.expiresSuffix}`) || now+1)
			if(now>=expires){
				this.remove(key)
				return ''
			}
			return this.store.getItem(key)?JSON.parse(this.store.getItem(key)):this.store.getItem(key)
		}
		/**
		 * @param {Object} key
		 * @param {Object} value
		 * @param {Object} expires 过期时间，按分钟计算
		 */
		set(key,value,expires){
			const now = Date.now()
			key = this.getKey(key)
			value = JSON.stringify(value)
			this.store.setItem(key,value)
			// 设置过期时间:当前时间+过期时间
			if(expires){
				this.store.setItem(`${key}${this.options.expiresSuffix}`,now + 1000*60*expires)
			}
		}
		remove(key){
			this.store.removeItem(key)
			this.store.removeItem(`${key}${this.options.expiresSuffix}`)
		}
		getKey(key){
			return this.options.nameSpace+key
		}
	}
	
	/**
	 * log 美化
	 */
	class Log{
		types(type = 'default'){
			var colors = {
				"default": "#515a6e",
				"primary": "#2d8cf0",
				"success": "#19be6b",
				"warning": "#ff9900",
				"error": "#ed4014",
			}
			return colors[type] || colors['default']
		}
		// 胶囊
		capsule(moduleName,logName,type){
			let prefixStyle = `background:#35495E;color:#fff;border-radius:3px 0 0 3px;padding:1px`
			let suffixStyle = `background:${this.types(type)};color:#fff;border-radius:0 3px 3px 0;padding:1px`
			/**
			 * 说明符%c应用CSS样式,有几个%c,后面参数就有几个样式的值
			 */
			console.log(`%c ${moduleName} %c ${logName} `, prefixStyle, suffixStyle)
		}
		default(moduleName,logName){
			this.capsule(moduleName,logName)
		}
		primary(moduleName,logName){
			this.capsule(moduleName,logName,'primary')
		}
		success(moduleName,logName){
			this.capsule(moduleName,logName,'success')
		}
		warning(moduleName,logName){
			this.capsule(moduleName,logName,'warning')
		}
		error(moduleName,logName){
			this.capsule(moduleName,logName,'error')
		}
	}
	// 捕获错误
	async function ErrorCapture(fn,logConfig={}){
		var _defaultLogConfig = {
			moduleName:'后台管理系统',
			logName:'完整日志内容',
			type:'primary'
		}
		_defaultLogConfig = Object.assign({},_defaultLogConfig,logConfig)
		try{
			let res = await fn()
			return [null,res]
		}catch(e){
			new Log().capsule(_defaultLogConfig.moduleName,_defaultLogConfig.logName,_defaultLogConfig.type)
			e.time = new Date()
			e.meta = {}
			e.meta.error = e.stack
			e.meta.url = window.location.href
			e.meta.user = {name:'hiegg',id:123213,access:'admin'}
			LogGroup(e)
			return [e,null]
		}
	}
	function LogGroup(e) {
		console.group("完整日志");
			console.log("message: ", e.message);
			if(e.time) console.log("time: ", e.time);
			if(e.name) console.log("type: ", e.name);
			if(e.meta) console.log("meta: ", e.meta);
		console.groupEnd()
	}
	let returnObj = {
		os,
		formatDate,
		getWeek,
		queryUrlParmas,
		formatPhone,
		formatMilli,
		deepCopy,
		merge,
		compose,
		Storage,
		Log,
		LogGroup,
		ErrorCapture
	}
	
	return Object.assign({},returnObj,utils)
})()
